package org.dashboard.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.dashboard.bean.*;
import org.dashboard.service.AdIndexService;
import org.dashboard.utils.CompressUtil;
import org.dashboard.utils.FileUtil;
import org.dashboard.utils.SerializeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.rmi.server.ExportException;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
@RequestMapping("/common/resource")
public class AdUploadController extends BaseController {
    private static final Logger logger = LoggerFactory.getLogger(AdUploadController.class);

    private static final String EXPORT_FOLDER = "export";
    private static final String RESOURCE_FOLDER = "resource";

    @Value("${web.upload.base.path}")
    private String uploadBasePath;


    @Reference
    private AdIndexService adIndexService;

    @RequestMapping(value = "/upload", method = RequestMethod.POST, produces = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ResponseBody
    public JsonResponse handleFileUpload(HttpServletRequest request, @RequestParam("file") MultipartFile file) {

        try {
            String filePathStr = request.getParameter("filePath");

            if (file.isEmpty()) {
                return JsonResponse.failed();
            }

            String[] filePathArray = filePathStr.split(",");
            String fullPath = uploadBasePath + File.separator + RESOURCE_FOLDER + File.separator + String.join(File.separator, filePathArray);
            File uploadFilePath = new File(fullPath);

            if (!uploadFilePath.exists()) {
                if (!uploadFilePath.mkdir()) {
                    return JsonResponse.failed();
                }
            }

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");

            String fileOriginalName = file.getOriginalFilename();
            String fileExtend = fileOriginalName.substring(fileOriginalName.lastIndexOf(".") + 1);
            String fileJustName = fileOriginalName.substring(0, fileOriginalName.lastIndexOf("."));

            String diskFileName = fileJustName + "_" + dateFormat.format(new Date()) + "." + fileExtend;
            String fileFullPath = fullPath + File.separator + diskFileName;

            byte[] bytes = file.getBytes();

            FileOutputStream fileOutputStream = new FileOutputStream(new File(fileFullPath));
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            bufferedOutputStream.write(bytes);
            bufferedOutputStream.close();

        } catch (IOException e) {
            logger.error("handleFileUpload", e);
        }

        return JsonResponse.success();
    }

    @RequestMapping(value = "/folder/delete", method = {RequestMethod.POST, RequestMethod.GET}, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ResponseBody
    public JsonResponse folderDelete(HttpServletRequest request) {

        String folderPathStr = request.getParameter("folderPath");
        String folderNameStr = request.getParameter("folderName");

        String[] filePathArray = folderPathStr.split(",");
        String parentPath = uploadBasePath + File.separator + RESOURCE_FOLDER + File.separator + String.join(File.separator, filePathArray);
        String deleteTargetPath = parentPath + File.separator + folderNameStr;
        File deleteFilePath = new File(deleteTargetPath);
        if (deleteFilePath.exists() && deleteFilePath.isDirectory()) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            String deleteFlagPath = parentPath + File.separator + "[DELETE]" + folderNameStr + dateFormat.format(new Date());
            if (!deleteFilePath.renameTo(new File(deleteFlagPath))) {
                return JsonResponse.failed();
            }
        }

        File parentFilePath = new File(parentPath);
        String[] folderList = parentFilePath.list((current, name) -> new File(current, name).isDirectory());

        JsonResponse jsonResponse = new JsonResponse();
        jsonResponse.setData(folderList);

        jsonResponse.setCode(1);
        jsonResponse.setResult("success");
        return jsonResponse;
    }


    @RequestMapping(value = "/folder/create", method = {RequestMethod.POST, RequestMethod.GET}, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ResponseBody
    public JsonResponse folderCreate(HttpServletRequest request) {

        String folderPathStr = request.getParameter("folderPath");
        String folderNameStr = request.getParameter("folderName");

        String[] filePathArray = folderPathStr.split(",");
        String parentPath = uploadBasePath + File.separator + RESOURCE_FOLDER + File.separator + String.join(File.separator, filePathArray);
        String fullPath = parentPath + File.separator + folderNameStr;
        File createFilePath = new File(fullPath);
        if (!createFilePath.exists()) {
            if (!createFilePath.mkdir()) {
                return JsonResponse.failed();
            }
        }

        File parentFilePath = new File(parentPath);
        String[] folderList = parentFilePath.list((current, name) -> new File(current, name).isDirectory());

        JsonResponse jsonResponse = new JsonResponse();
        jsonResponse.setData(folderList);

        jsonResponse.setCode(1);
        jsonResponse.setResult("success");
        return jsonResponse;
    }


    @RequestMapping(value = "/folder/rename", method = {RequestMethod.POST, RequestMethod.GET}, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ResponseBody
    public JsonResponse folderRename(HttpServletRequest request) {

        String folderPathStr = request.getParameter("folderPath");
        String folderNameStr = request.getParameter("folderName");
        String folderNewNameStr = request.getParameter("folderNewName");

        String[] filePathArray = folderPathStr.split(",");
        String parentPath = uploadBasePath + File.separator + RESOURCE_FOLDER + File.separator + String.join(File.separator, filePathArray);
        String renameTargetPath = parentPath + File.separator + folderNameStr;
        File renameFilePath = new File(renameTargetPath);
        if (renameFilePath.exists()) {
            String renameNewPath = parentPath + File.separator + folderNewNameStr;
            if (!renameFilePath.renameTo(new File(renameNewPath))) {
                return JsonResponse.failed();
            }
        }

        File parentFilePath = new File(parentPath);
        String[] folderList = parentFilePath.list((current, name) -> new File(current, name).isDirectory());

        JsonResponse jsonResponse = new JsonResponse();
        jsonResponse.setData(folderList);

        jsonResponse.setCode(1);
        jsonResponse.setResult("success");
        return jsonResponse;
    }

    @RequestMapping(value = "/folder/list", method = {RequestMethod.POST, RequestMethod.GET}, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ResponseBody
    public JsonResponse folderList(HttpServletRequest request) {

        String folderPathStr = request.getParameter("folderPath");

        String[] filePathArray = folderPathStr.split(",");
        String parentPath = uploadBasePath + File.separator + RESOURCE_FOLDER + File.separator + String.join(File.separator, filePathArray);

        File parentFilePath = new File(parentPath);
        String[] folderList = parentFilePath.list((current, name) -> new File(current, name).isDirectory());

        JsonResponse jsonResponse = new JsonResponse();
        jsonResponse.setData(folderList);

        jsonResponse.setCode(1);
        jsonResponse.setResult("success");
        return jsonResponse;
    }


    @RequestMapping(value = "/file/list", method = {RequestMethod.POST, RequestMethod.GET}, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ResponseBody
    public JsonResponse fileList(HttpServletRequest request) {

        String folderPathStr = request.getParameter("folderPath");

        String[] filePathArray = folderPathStr.split(",");
        String parentPath = uploadBasePath + File.separator + RESOURCE_FOLDER + File.separator + String.join(File.separator, filePathArray);

        File parentFilePath = new File(parentPath);
        String[] fileList = parentFilePath.list((current, name) -> new File(current, name).isFile());

        JsonResponse jsonResponse = new JsonResponse();
        jsonResponse.setData(fileList);

        jsonResponse.setCode(1);
        jsonResponse.setResult("success");
        return jsonResponse;
    }


    @RequestMapping(value = "/file/delete", method = {RequestMethod.POST, RequestMethod.GET}, produces = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    @ResponseBody
    public JsonResponse fileDelete(HttpServletRequest request) {

        String folderPathStr = request.getParameter("folderPath");
        String fileNameStr = request.getParameter("fileName");

        String[] filePathArray = folderPathStr.split(",");
        String parentPath = uploadBasePath + File.separator + RESOURCE_FOLDER + File.separator + String.join(File.separator, filePathArray);
        String deleteTargetFile = parentPath + File.separator + fileNameStr;
        File deleteFile = new File(deleteTargetFile);
        if (deleteFile.exists() && deleteFile.isFile()) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            String deleteFlagFile = parentPath + File.separator + "[DELETE]" + fileNameStr + dateFormat.format(new Date());
            if (!deleteFile.renameTo(new File(deleteFlagFile))) {
                return JsonResponse.failed();
            }
        }

        File parentFilePath = new File(parentPath);
        String[] folderList = parentFilePath.list((current, name) -> new File(current, name).isDirectory());

        JsonResponse jsonResponse = new JsonResponse();
        jsonResponse.setData(folderList);

        jsonResponse.setCode(1);
        jsonResponse.setResult("success");
        return jsonResponse;
    }


    @RequestMapping(value = "/page/export", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public JsonResponse pageExport(HttpServletRequest request) throws IOException {

        try {
            Integer pageId = Integer.parseInt(request.getParameter("pageId"));
            Map<String, Object> data = adIndexService.exportPage(pageId);
            String rootPath = uploadBasePath + File.separator + EXPORT_FOLDER;
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
            String pathName = dateFormat.format(new Date());
            String parentPath = rootPath + File.separator + pathName;
            File exportFilePath = new File(parentPath);
            if (!exportFilePath.exists()) {
                if (!exportFilePath.mkdir()) {
                    return JsonResponse.failed();
                }
            }

            String pageFilePath = parentPath + File.separator + "page.json";
            AdPage adPage = (AdPage) data.get("page");
            FileUtil.writeString(new File(pageFilePath), SerializeUtil.beanToJsonByFastjson(adPage, null));

            String chartsPath = parentPath + File.separator + "charts";
            String datasetsPath = parentPath + File.separator + "datasets";
            String schemasPath = parentPath + File.separator + "schemas";
            if (!new File(chartsPath).mkdir()
                    || !new File(datasetsPath).mkdir()
                    || !new File(schemasPath).mkdir()) {
                return JsonResponse.failed();
            }

            List<AdChart> chartList = (List<AdChart>) data.get("charts");
            if (chartList != null && chartList.size() > 0) {
                for (AdChart adChart : chartList) {
                    String chartsFilePath = chartsPath + File.separator + adChart.getChartId() + ".json";
                    FileUtil.writeString(new File(chartsFilePath), SerializeUtil.beanToJsonByFastjson(adChart, null));
                }
            }

            List<AdDataset> datasetList = (List<AdDataset>) data.get("datasets");
            if (datasetList != null && datasetList.size() > 0) {
                for (AdDataset adDataset : datasetList) {
                    String datasetsFilePath = datasetsPath + File.separator + adDataset.getDatasetId() + ".json";
                    FileUtil.writeString(new File(datasetsFilePath), SerializeUtil.beanToJsonByFastjson(adDataset, null));
                }
            }

            List<AdSchema> schemaList = (List<AdSchema>) data.get("schemas");
            if (schemaList != null && schemaList.size() > 0) {
                for (AdSchema adSchema : schemaList) {
                    String schemasFilePath = schemasPath + File.separator + adSchema.getSchemaId() + ".json";
                    FileUtil.writeString(new File(schemasFilePath), SerializeUtil.beanToJsonByFastjson(adSchema, null));
                }
            }

            String targeZipFile = parentPath + ".data";
            CompressUtil.compressAll(targeZipFile, pageFilePath, chartsPath, datasetsPath, schemasPath);

            String downloadFilePath = "/static/export/" + pathName + ".data";

            JsonResponse jsonResponse = new JsonResponse();
            jsonResponse.setData(downloadFilePath);

            jsonResponse.setCode(1);
            jsonResponse.setResult("success");
            return jsonResponse;
        } catch (Exception e) {
            logger.error("pageExport", e);
            return JsonResponse.failed();
        }
    }

    @RequestMapping(value = "/page/import", method = RequestMethod.POST, produces = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ResponseBody
    public JsonResponse pageImport(HttpServletRequest request, @RequestParam("file") MultipartFile file) {

        try {
            Integer pageId = Integer.parseInt(request.getParameter("pageId"));

            boolean import_charts = Boolean.parseBoolean(request.getParameter("import_charts"));
            boolean import_datasets = Boolean.parseBoolean(request.getParameter("import_datasets"));
            boolean import_schemas = Boolean.parseBoolean(request.getParameter("import_schemas"));

            if (file.isEmpty()) {
                return JsonResponse.failed();
            }

            String fullPath = uploadBasePath + File.separator + EXPORT_FOLDER;
            File uploadFilePath = new File(fullPath);

            if (!uploadFilePath.exists()) {
                if (!uploadFilePath.mkdir()) {
                    return JsonResponse.failed();
                }
            }

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");

            String fileOriginalName = file.getOriginalFilename();
            String fileExtend = fileOriginalName.substring(fileOriginalName.lastIndexOf(".") + 1);
            String fileJustName = fileOriginalName.substring(0, fileOriginalName.lastIndexOf("."));

            String diskFileName = fileJustName + "_" + dateFormat.format(new Date());
            String fileFullPath = fullPath + File.separator + diskFileName + "." + fileExtend;

            byte[] bytes = file.getBytes();

            FileOutputStream fileOutputStream = new FileOutputStream(new File(fileFullPath));
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            bufferedOutputStream.write(bytes);
            bufferedOutputStream.close();

            String targetPath = fullPath + File.separator + diskFileName;
            CompressUtil.decompress(fileFullPath, targetPath);

            String pageFullPath = targetPath + File.separator + "page.json";
            String chartsPath = targetPath + File.separator + "charts";
            String datasetsPath = targetPath + File.separator + "datasets";
            String schemasPath = targetPath + File.separator + "schemas";

            AdPage adPage = (AdPage) SerializeUtil.jsonToBeanByFastjson(FileUtil.readBytesToString(new File(pageFullPath)), AdPage.class);
            List<AdChart> adChartList = new ArrayList<>();
            List<AdDataset> adDatasetList = new ArrayList<>();
            List<AdSchema> adSchemaList = new ArrayList<>();

            if (import_charts) {
                File chartsFolder = new File(chartsPath);
                if (chartsFolder.exists()) {
                    File[] listOfFiles = chartsFolder.listFiles();
                    if (listOfFiles != null) {
                        for (File chartFile : listOfFiles) {
                            adChartList.add((AdChart) SerializeUtil.jsonToBeanByFastjson(FileUtil.readBytesToString(chartFile), AdChart.class));
                        }
                    }
                }
            }

            if (import_datasets) {
                File datasetsFolder = new File(datasetsPath);
                if (datasetsFolder.exists()) {
                    File[] listOfFiles = datasetsFolder.listFiles();
                    if (listOfFiles != null) {
                        for (File datasetFile : listOfFiles) {
                            adDatasetList.add((AdDataset) SerializeUtil.jsonToBeanByFastjson(FileUtil.readBytesToString(datasetFile), AdDataset.class));
                        }
                    }
                }
            }

            if (import_schemas) {
                File schemasFolder = new File(schemasPath);
                if (schemasFolder.exists()) {
                    File[] listOfFiles = schemasFolder.listFiles();
                    if (listOfFiles != null) {
                        for (File schemaFile : listOfFiles) {
                            adSchemaList.add((AdSchema) SerializeUtil.jsonToBeanByFastjson(FileUtil.readBytesToString(schemaFile), AdSchema.class));
                        }
                    }
                }
            }

            Map<String, Object> data = new HashMap<>();
            data.put("page", adPage);
            data.put("charts", adChartList);
            data.put("datasets", adDatasetList);
            data.put("schemas", adSchemaList);

            adIndexService.importPage(pageId, data);
            return JsonResponse.success();

        } catch (IOException e) {
            logger.error("pageImport", e);
            return JsonResponse.failed();
        }

    }


}
